#include "fsmc.h"
#include "SPI_INIT.h"
#include "usbd_cdc.h"
#include "stdlib.h" 


//typedef struct
//{
//	vu16 FSMC_REG;
//	vu16 FSMC_RAM;
//} LCD_TypeDef;

////使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A18作为数据命令区分线
////注意设置时STM32内部会右移一位对其 			    
//#define LCD_BASE        ((u32)(0x60000000 | 0x0007FFFE))
//#define LCD             ((LCD_TypeDef *) LCD_BASE)


SRAM_HandleTypeDef SRAM_Handler;	//SRAM句柄

void write_cmd(unsigned short cmd)
{	
	FSMC_REG = cmd;	
	delay_6ns(1);
}

void Write_DATA(unsigned short data_code )
{	
	FSMC_RAM = data_code;
	delay_6ns(1); //重要勿删
}

void MCU_2832_write_CMD(u8 channel,u16 cmd)
{	
    SPI_CS_Select(channel,0);
    FSMC_REG = cmd;
    SPI_CS_Select(channel,1);
}

void MCU_2832_write_CMD_NOCS(u16 cmd)
{	
    FSMC_REG = cmd;
}


void MCU_2832_Write_Data(u8 channel,u16 data_code )
{	
	u16 i = 1300;	
	SPI_CS_Select(channel,0);
	FSMC_RAM = data_code;
	while(i--);
	i = 1300;		
	SPI_CS_Select(channel,1);  
	while(i--); 	
}


u16 MCU_2832_Read_Data(u8 channel)
{	
    u16 i = 1300;
    u16  data_code;
    SPI_CS_Select(channel,0);
    data_code = FSMC_RAM;
    while(i--);
    i = 1300;
    SPI_CS_Select(channel,1);
    while(i--);  
    return data_code;
    
}

//fsmc 发送纯色画面，DEBUG模式使用
void FSMC_Pure_colour(u32 Color)
{
	if(OLED.SigMode == CMD_Mode)            //Command logic 纯色
	{
		SSD2828_W_CMD_LOGIC_Pure_Color(OLED.pixel_clk,OLED.SigMode,0,OLED.H_pixel,OLED.V_pixel,Color); //Command模式逻辑图
	}
	else
	{
		write_cmd(0x5678);						//将OLED时序数据发送到FPGA
		delay_us(4);
		write_cmd((u16)(((OLED.RGBMode==2)?3:1)<<8)|((Color&0xff0000)>>16));
		delay_us(4);
		write_cmd((u16)(Color&0x00ffff));
		delay_us(4);
		write_cmd(0x8765);
		delay_us(4);
	}
}


void FSMC_Pure_Pic(u16 PIC_NUM)
{
	if(OLED.SigMode == CMD_Mode)            //Command 模式
	{
		SSD2828_W_LOGIC_Pic(OLED.pixel_clk,OLED.SigMode,0,OLED.H_pixel,OLED.V_pixel,PIC_NUM);
	}	
	else
	{
		write_cmd(0x6789);						//将OLED时序数据发送到FPGA
		delay_us(4);
		write_cmd((0x4<<8)|PIC_NUM);
		delay_us(4);
		write_cmd(0x9876);
		delay_us(4);
	}
}

void FSMC_Edit_Logic_Pic(u16 PIC_NUM,u32 Color_M,u32 Color_L,u16 X0,u16 X1,u16 Y0,u16 Y1,u16 R0)
{
	if(OLED.SigMode == CMD_Mode)            //Command 模式
	{
		SSD2828_W_CMD_EDIT_LOGIC_Pic(OLED.pixel_clk,OLED.SigMode,0,OLED.H_pixel,OLED.V_pixel,PIC_NUM,Color_M,Color_L,X0,X1,Y0,Y1,R0);
	}	
	else
	{
		write_cmd(0x1122);			delay_us(4);					//将OLED时序数据发送到FPGA
		write_cmd((0x4<<8)|PIC_NUM);		delay_us(4);
		write_cmd((u16)(Color_M>>8));		delay_us(4);	
		write_cmd((u16)(((Color_M&0x0000ff)<<8)|((Color_L&0xff0000)>>16)));		delay_us(4);	
		write_cmd((u16)(Color_L&0x00ffff));		delay_us(4);	
		write_cmd(X0);		delay_us(4);
		write_cmd(X1);		delay_us(4);
		write_cmd(Y0);		delay_us(4);
		write_cmd(Y1);		delay_us(4);	
		write_cmd(R0);		delay_us(4);		
		write_cmd(0x2211);	delay_us(4);
	}
}


//fsmc 
void FSMC_BMP_NUM(u8 BMP_NUM)
{
	write_cmd(0x4567);						//将OLED时序数据发送到FPGA
	delay_us(40);
	//write_cmd(BMP_NUM);	  //
	write_cmd((((OLED.RGBMode==2)?2:0)<<8) |BMP_NUM);	  //
	delay_us(40);
	write_cmd(0x7654);	
	delay_us(40);
}

void FSMC_OLED_Parameter(u32* buf,u8 SigMode)
{
    write_cmd(0x1234);						//将OLED时序数据发送到FPGA
    for(i = 0;i < 4;i ++)
    {
        write_cmd(buf[i+8]>>16);				//	0:H_PIXEL	1:H_B	2:H_F	3:H_S	4:高8(单双6,8)
        write_cmd(buf[i+8]);						//	0:V_PIXEL	1:V_B	2:V_F	3:V_S	4:无效
    }
    write_cmd(((buf[12]>>16)&0xff00)+((SigMode == Video_Mode) ? 0x00 : 0x01));				//	高8(单双6,8)
    write_cmd(buf[14]>>24);				//	无效  0:video  1:Command
    write_cmd(0x4321);			  
}

void FSMC_Open(u16 Init_Mode)
{
	write_cmd(0x2345);	
	delay_us(4);	
	write_cmd(Init_Mode);	
	delay_us(4);
	write_cmd(0x5432);	
}


//配置MPU的region（SRAM区域为透写模式）
void LCD_MPU_Config(void)
{	
	MPU_Region_InitTypeDef MPU_Initure;

	HAL_MPU_Disable();							//配置MPU之前先关闭MPU,配置完成之后再使能MPU	
	//外部SRAM为region0，大小为2MB,此区域可读写
	MPU_Initure.CFEnable =MPU_REGION_ENABLE;	    //使能region
	MPU_Initure.Number=LCD_REGION_NUMBER;		//设置region，外部sram使用的regions
	MPU_Initure.BaseAddress=LCD_ADDRESS_START;	//region基地址
	MPU_Initure.Size=LCD_REGION_SIZE;			//region大小
	MPU_Initure.SubRegionDisable=0X00;
	MPU_Initure.TypeExtField=MPU_TEX_LEVEL0;
	MPU_Initure.AccessPermission=MPU_REGION_FULL_ACCESS;	//´Ëregion¿É¶ÁÐ´
	MPU_Initure.DisableExec=MPU_INSTRUCTION_ACCESS_ENABLE;	//ÔÊÐí¶ÁÈ¡´ËÇøÓòÖÐµÄÖ¸Áî
	MPU_Initure.IsShareable=MPU_ACCESS_NOT_SHAREABLE;
	MPU_Initure.IsCacheable=MPU_ACCESS_NOT_CACHEABLE;
	MPU_Initure.IsBufferable=MPU_ACCESS_BUFFERABLE;
	
	HAL_MPU_ConfigRegion(&MPU_Initure);
	HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);     //¿ªÆôMPU
}
//SRAM底层驱动，时钟使能，引脚分配
//此函数会被HAL_SRAM_Init()调用
//hsram:SRAM句柄
void HAL_SRAM_MspInit(SRAM_HandleTypeDef *hsram)
{
    GPIO_InitTypeDef GPIO_Initure;
	__HAL_RCC_FMC_CLK_ENABLE();				//使能FMC时钟
    __HAL_RCC_GPIOD_CLK_ENABLE();			//开启GPIOB时钟
    __HAL_RCC_GPIOE_CLK_ENABLE();			//开启GPIOE时钟
    __HAL_RCC_GPIOG_CLK_ENABLE();			//开启GPIOG时钟
    __HAL_RCC_GPIOF_CLK_ENABLE();			//开启GPIOF时钟	
	
	//初始化PD0,1,4,5,7,8,9,10,13,14,15
	GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_7|GPIO_PIN_8|
                     GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14|GPIO_PIN_15;
	GPIO_Initure.Mode=GPIO_MODE_AF_PP; 		//推挽复用
	GPIO_Initure.Pull=GPIO_PULLUP;			//上拉
	GPIO_Initure.Speed=GPIO_SPEED_MEDIUM;	//高速
	GPIO_Initure.Alternate=GPIO_AF12_FMC;	//复用为FMC
	HAL_GPIO_Init(GPIOD,&GPIO_Initure);     //初始化
	
	//初始化PE7,8,9,10,11,12,13,14,15
	GPIO_Initure.Pin=GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|
                     GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
	HAL_GPIO_Init(GPIOE,&GPIO_Initure);
	
	GPIO_Initure.Pin =  GPIO_PIN_0;
	HAL_GPIO_Init(GPIOF, &GPIO_Initure);	
	
	GPIO_Initure.Pin =  GPIO_PIN_12;
	HAL_GPIO_Init(GPIOG, &GPIO_Initure);	
}


void FSMC_IO_init(void)
{	
	//GPIO_InitTypeDef GPIO_Initure;
	FMC_NORSRAM_TimingTypeDef FSMC_ReadWriteTim;
	FMC_NORSRAM_TimingTypeDef FSMC_WriteTim;	

	LCD_MPU_Config();
	SRAM_Handler.Instance=FMC_NORSRAM_DEVICE;       
	SRAM_Handler.Extended=FMC_NORSRAM_EXTENDED_DEVICE;       

	SRAM_Handler.Init.NSBank=FMC_NORSRAM_BANK4;     				//Bank4
	SRAM_Handler.Init.DataAddressMux=FMC_DATA_ADDRESS_MUX_ENABLE; 	//不复用数据线
	SRAM_Handler.Init.MemoryType=FMC_MEMORY_TYPE_SRAM;   			//SRAM
	SRAM_Handler.Init.MemoryDataWidth=FMC_NORSRAM_MEM_BUS_WIDTH_16; //16位数据宽度
	SRAM_Handler.Init.BurstAccessMode=FMC_BURST_ACCESS_MODE_DISABLE;
	SRAM_Handler.Init.WaitSignalPolarity=FMC_WAIT_SIGNAL_POLARITY_LOW;
	SRAM_Handler.Init.AsynchronousWait=FMC_ASYNCHRONOUS_WAIT_DISABLE;
	SRAM_Handler.Init.WaitSignal=FMC_WAIT_SIGNAL_DISABLE;
	SRAM_Handler.Init.WriteBurst=FMC_WRITE_BURST_DISABLE;

	SRAM_Handler.Init.WriteOperation=FMC_WRITE_OPERATION_ENABLE;    //寄存器写使能
	SRAM_Handler.Init.ExtendedMode=FMC_EXTENDED_MODE_ENABLE;        //读写使用不同的时序	


	//FSMC读时序控制寄存器
	FSMC_ReadWriteTim.AddressSetupTime=0x04; //15    	//地址建立时间（ADDSET）为15个HCLK 1/216M =4.6ns*15=69ns
	FSMC_ReadWriteTim.AddressHoldTime=0x04;
	FSMC_ReadWriteTim.DataSetupTime=0x1F;   //80    	//数据保存时间（DATAST）为85个HCLK 1/216M	=4.6*80=368ns
	FSMC_ReadWriteTim.BusTurnAroundDuration=0x00;	
	FSMC_ReadWriteTim.CLKDivision=0x08;	
	FSMC_ReadWriteTim.DataLatency=0x00;
	FSMC_ReadWriteTim.AccessMode=FMC_ACCESS_MODE_A; //模式A

	//FSMC写时序控制寄存器
	FSMC_WriteTim.AddressSetupTime=0x4;  //15    08  	//地址建立时间（ADDSET）为15个HCLK=69ns
	FSMC_WriteTim.AddressHoldTime=0x4;//0a
	FSMC_WriteTim.DataSetupTime=0xe;//0x0f;  //15  0f        	//数据保存时间（DATAST）为4.6ns*15¸öHCLK=69ns
	FSMC_WriteTim.BusTurnAroundDuration=0x0;	
	FSMC_WriteTim.CLKDivision=0x04;//0x08;	
	FSMC_WriteTim.DataLatency=0x04;	
	FSMC_WriteTim.AccessMode=FMC_ACCESS_MODE_A;	//模式A
	HAL_SRAM_MspInit(&SRAM_Handler);
	HAL_SRAM_Init(&SRAM_Handler,&FSMC_ReadWriteTim,&FSMC_WriteTim);		
	delay_ms(50); // delay 50 ms 	
}

